package org.zeroes.svg;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.zeroes.cons.ZSGameManager;

import java.io.InputStream;
public class DomParser {

	//No generics
	List<Employee> myEmpls;
public 	List<SVGElement> nodes;
public	List<SVGElement> layers;
public	List<SVGElement> groups;
public List<SVGElement> rects;
public List<SVGElement> paths;
public List<SVGElement> clones;
	Document dom;


	public DomParser(InputStream is){
		//create a list to hold the employee objects
		myEmpls = new ArrayList<Employee>();
		nodes = new ArrayList<SVGElement>();
		layers = new ArrayList<SVGElement>();
		groups = new ArrayList<SVGElement>();
		rects = new ArrayList<SVGElement>();
		paths = new ArrayList<SVGElement>();
		clones = new ArrayList<SVGElement>();
		//parse the xml file and get the dom object
		parseXmlFile(is);
		
		//get each employee element and create a Employee object
		parseDocument();
		
		//Iterate through the list and print the data
		printData();
	}

	public void runExample() {
		
		//parse the xml file and get the dom object
	//	parseXmlFile();
		
		//get each employee element and create a Employee object
		parseDocument();
		
		//Iterate through the list and print the data
		printData();
		
	}
	
	
	private void parseXmlFile(InputStream is){
		//get the factory
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		
		try {
			
			//Using factory get an instance of document builder
			DocumentBuilder db = dbf.newDocumentBuilder();
			
			//parse using builder to get DOM representation of the XML file
			dom = db.parse(is);
		

		}catch(ParserConfigurationException pce) {
			pce.printStackTrace();
		}catch(SAXException se) {
			se.printStackTrace();
		}catch(IOException ioe) {
			ioe.printStackTrace();
		}
	}

	
	private void parseDocument(){
		//get the root elememt
		Element docEle = dom.getDocumentElement();
		
		// root
		NodeList svgl = docEle.getElementsByTagName("svg");
		Element elsvgr = (Element)svgl.item(0);
		String sH="",sW="",sO="landscape";
		if(elsvgr.hasAttribute("height")){
			
			 sH = elsvgr.getAttribute("height");
		}
		if(elsvgr.hasAttribute("width")){
			
			 sW = elsvgr.getAttribute("width");
		}
		
		int w = (Integer.valueOf(sW).intValue());
		int h = (Integer.valueOf(sH).intValue());
		ZSGameManager.AskMe().setDesignScreenSize(w, h);
		//rects
		NodeList rl = docEle.getElementsByTagName("rect");
		if(rl != null && rl.getLength() > 0) {
			for(int i = 0 ; i < rl.getLength();i++) {
				
				//get the employee element
				Element elr = (Element)rl.item(i);
				
				//get the Employee object
				SVGElement er = getSVGRectElement(elr);
				
				//add it to list
		
				rects.add(er);
					
			}
		}
		
		//paths
		NodeList pl = docEle.getElementsByTagName("path");
		if(pl != null && pl.getLength() > 0) {
			for(int i = 0 ; i < pl.getLength();i++) {
				
				//get the employee element
				Element elp = (Element)pl.item(i);
				
				//get the Employee object
				SVGElement ep = getSVGPathElement(elp);
				
				//add it to list
		
				paths.add(ep);
					
			}
		}
		
		//get a nodelist of <employee> elements
		NodeList nl = docEle.getElementsByTagName("image");
		if(nl != null && nl.getLength() > 0) {
			for(int i = 0 ; i < nl.getLength();i++) {
				
				//get the employee element
				Element el = (Element)nl.item(i);
				
				//get the Employee object
				SVGElement e = getSVGElement(el);
				
				//add it to list
				nodes.add(e);
			}
		}
		
		// clones
		
		NodeList cl = docEle.getElementsByTagName("use");
		if(cl != null && cl.getLength() > 0) {
			for(int i = 0 ; i < cl.getLength();i++) {
				
				//get the employee element
				Element cel = (Element)cl.item(i);
				
				//get the Employee object
				SVGElement c = getSVGCloneElement(cel);
				
				//add it to list
				clones.add(c);
			}
		}
		
		// layers
		NodeList ll = docEle.getElementsByTagName("g");
		if(ll != null && ll.getLength() > 0) {
			for(int i = 0 ; i < ll.getLength();i++) {
				
				//get the employee element
				Element ell = (Element)ll.item(i);
				
				//get the Employee object
				SVGElement e = getSVGLayerElement(ell);
				
				//add it to list
				if(e.type==SVGElement.TYPE_GROUP)
					{
					groups.add(e);
					}
				else{
				layers.add(e);
					}
			}
		}
		

		
		
	}

	private SVGElement getSVGLayerElement(Element svgnode) {
		String gm="",trs="";
		
		SVGElement node=new SVGElement("");
		if(svgnode.hasAttribute("inkscape:groupmode"))
			gm = svgnode.getAttribute("inkscape:groupmode");
		if(svgnode.hasAttribute("transform")){
			trs = svgnode.getAttribute("transform");
		node.setTRS(trs);
		}

		if (gm.equals("layer")){
			node.setID(svgnode.getAttribute("inkscape:label"));
			node.parentID="root";
			if(svgnode.hasAttribute("Batch")){
				node.type=SVGElement.TYPE_BATCH_LAYER;
			}
		}
		else{
			node.setID(svgnode.getAttribute("id"));
			node.type=SVGElement.TYPE_GROUP;
			Element parent=(Element)svgnode.getParentNode();
			if(parent.hasAttribute("inkscape:groupmode"))
			node.parentID=parent.getAttribute("inkscape:label");
			else
				node.parentID="UNKNOWN";	
		}
		
		return node;
	}
	
	private SVGElement getSVGRectElement(Element svgnode){
		
		String xx = svgnode.getAttribute("x");
		String yy = svgnode.getAttribute("y");
		String id = svgnode.getAttribute("id");
		String w = svgnode.getAttribute("width");
		String h = svgnode.getAttribute("height");
		SVGElement node = new SVGElement(xx,yy,w,h,id,"UNKNOWN");
		Element parent=(Element)svgnode.getParentNode();
		if(parent.hasAttribute("inkscape:groupmode"))
		{
		node.parentID=parent.getAttribute("inkscape:label");
		if(parent.hasAttribute("Batch")){
			node.type=SVGElement.TYPE_BATCH_LAYER_RECT;
		}
		}
		return node;
	}
	
	private SVGElement getSVGPathElement(Element svgnode){
		

		String id = svgnode.getAttribute("id");
		String data = svgnode.getAttribute("d");
	
		SVGElement node = new SVGElement(id,data);

		return node;
	}
	
	private SVGElement getSVGCloneElement(Element svgnode){
		
		String trs="",style="",zz="0";

		String _id = svgnode.getAttribute("id");
		String tg = svgnode.getAttribute("xlink:href");
		if(svgnode.hasAttribute("transform"))
			trs = svgnode.getAttribute("transform");
		SVGElement node = new SVGElement(_id,tg,trs,nodes);
		Element parent=(Element)svgnode.getParentNode();
		if(parent.hasAttribute("inkscape:groupmode"))
		{
		node.parentID=parent.getAttribute("inkscape:label");
		}
		else
		{
			node.parentID=parent.getAttribute("id");
		}
		return node;
	}
	
	
	
	private SVGElement getSVGElement(Element svgnode) {
		
		String trs="",style="",zz="0",data="";
		String xx = svgnode.getAttribute("x");
		String yy = svgnode.getAttribute("y");
		String _id = svgnode.getAttribute("id");
		String rd = svgnode.getAttribute("xlink:href");
		if(svgnode.hasAttribute("transform"))
			trs = svgnode.getAttribute("transform");

		SVGElement node = new SVGElement(xx,yy,_id,rd,trs);
		if(svgnode.hasAttribute("style")){
			style = svgnode.getAttribute("style");
		node.setStyle(style);
		}
		if(svgnode.hasAttribute("data")){
			data = svgnode.getAttribute("data");
		node.setCustomData(data);
		}
		if(svgnode.hasAttribute("z")){
			zz = svgnode.getAttribute("z");
		node.setZ(zz);
		}
		
		Element parent=(Element)svgnode.getParentNode();
		if(parent.hasAttribute("inkscape:groupmode"))
		{
		node.parentID=parent.getAttribute("inkscape:label");
		if(parent.hasAttribute("Batch")){
			if(svgnode.hasAttribute("clip-path")){
			String cp = svgnode.getAttribute("clip-path");
				if(cp.equals("none"))
					node.type=SVGElement.TYPE_TEXTURE_ATLAS_IMAGE;	
				else{
				node.type=SVGElement.TYPE_TEXTURE_ATLAS_INSTANCE;
				// parse clip-path
				node.linkedElem=this.parseClipPath(cp);
				}
			}
			else
				node.type=SVGElement.TYPE_TEXTURE_ATLAS_IMAGE;	
		}
		else
		{
			node.type=SVGElement.TYPE_FREE_IMAGE;	
		}
		}
		else
		{
			Element gparent=(Element)parent.getParentNode();
			if(gparent.hasAttribute("Batch")){
				node.parentID=parent.getAttribute("id");
				String _cp=null;
				if(svgnode.hasAttribute("clip-path")){
				_cp = svgnode.getAttribute("clip-path");
				}
				
				node.linkedElem=this.parseClipPath(_cp);
				node.type=SVGElement.TYPE_TEXTURE_ATLAS_GROUPEDINSTANCE;
			}
			else
			{
			node.parentID=parent.getAttribute("id");
			node.type=SVGElement.TYPE_GROUPED_IMAGE;
		}
		}
		return node;
	}
	
	public SVGElement getNodeById(String _id){
		//Iterator it = nodes.iterator();
	//	int i=0;
	
	  int i;
	  String s="";
	  for(i=0;i<nodes.size();++i){
		  s=nodes.get(i).id;
		  if (s.equals(_id)){
			  return nodes.get(i);
		  }
	  }

		
		return null;
		
	}
	
	public SVGElement getPathById(String _id){
		//Iterator it = nodes.iterator();
	//	int i=0;
	
	  int i;
	  String s="";
	  for(i=0;i<paths.size();++i){
		  s=paths.get(i).id;
		  if (s.equals(_id)){
			  return paths.get(i);
		  }
	  }

		
		return null;
		
	}

	/**
	 * I take an employee element and read the values in, create
	 * an Employee object and return it
	 * @param empEl
	 * @return
	 */
	private Employee getEmployee(Element empEl) {
		
		//for each <employee> element get text or int values of 
		//name ,id, age and name
		String name = getTextValue(empEl,"Name");
		int id = getIntValue(empEl,"Id");
		int age = getIntValue(empEl,"Age");

		String type = empEl.getAttribute("type");
		
		//Create a new Employee with the value read from the xml nodes
		Employee e = new Employee(name,id,age,type);
		
		return e;
	}


	/**
	 * I take a xml element and the tag name, look for the tag and get
	 * the text content 
	 * i.e for <employee><name>John</name></employee> xml snippet if
	 * the Element points to employee node and tagName is name I will return John  
	 * @param ele
	 * @param tagName
	 * @return
	 */
	private String getTextValue(Element ele, String tagName) {
		String textVal = null;
		NodeList nl = ele.getElementsByTagName(tagName);
		if(nl != null && nl.getLength() > 0) {
			Element el = (Element)nl.item(0);
			textVal = el.getFirstChild().getNodeValue();
		}

		return textVal;
	}

	
	/**
	 * Calls getTextValue and returns a int value
	 * @param ele
	 * @param tagName
	 * @return
	 */
	private int getIntValue(Element ele, String tagName) {
		//in production application you would catch the exception
		return Integer.parseInt(getTextValue(ele,tagName));
	}
	
	/**
	 * Iterate through the list and print the 
	 * content to console
	 */
	private void printData(){
		
		System.out.println("No of Employees '" + myEmpls.size() + "'.");
		
		Iterator it = myEmpls.iterator();
		while(it.hasNext()) {
			System.out.println(it.next().toString());
		}
	}

	
	public void parse(){
		//create an instance
	//	DomParser dpe = new DomParser();
		
		//call run example
		//dpe.runExample();
	}
	
	private SVGElement parseClipPath(String s){
		
		String ts = s.substring(5, s.length()-1);
		Element docEle = dom.getDocumentElement();
		NodeList nl = docEle.getElementsByTagName("clipPath");
		
		if(nl != null && nl.getLength() > 0) {
			for(int i = 0 ; i < nl.getLength();i++) {
		
				Element el = (Element)nl.item(i);
				String eid=el.getAttribute("id");
				if(eid.equals(ts)){
					NodeList cl=el.getChildNodes();
					Element efc = (Element)cl.item(1);
					float xx=(Float.valueOf(efc.getAttribute("x")).floatValue());
					float yy=(Float.valueOf(efc.getAttribute("y")).floatValue());
					for(SVGElement r:rects){
						if(r.x==xx&&r.y==yy&&(!r.id.equals(efc.getAttribute("id")))&&(!r.parentID.equals("UNKNOWN"))){
							return r;
							
						}
						
					}
					
				}
				
			}
		}
			return null;
	}

}
